#include "GameState.h"
#include "physicsBody.h"
#include "ball.h"
#include "score.h"
#include "position.h"
#include "GameObjectSystem.h"
#include "gameRulesComponent.h"
#include "physicsComponent.h"
#include "BulletDynamics/Dynamics/btRigidBody.h"
#include "bumper.h"

GameState::GameState(const ObjectId& stateId)
	:FSMState(stateId)
{
	m_collisionSubscriber = MV_NEW SubscriberHelper<CollisionObserver>(this);
	const PhysicsComponent* phyCmp = static_cast<const PhysicsComponent*>(GameObjectSystem::GetSingleton().getComponent("PhyCmp"));
	m_collisionSubscriber->Subscribe(phyCmp->getCollisionPublisher());
}

GameState::~GameState()
{
	MV_DELETE(m_collisionSubscriber);
}

void GameState::onEnter()
{
	m_rebounds = 0;
	m_StaticBumper = false;
}

void GameState::onFrame(real frametime, real timestep)
{
	checkBallHorizontalVelocity();
}

void GameState::CollisionEvent(const CollisionData& collisionData)
{
	GameObjectSystem& gameObjectSystem = GameObjectSystem::GetSingleton();

	const ObjectId& a = collisionData.getObjectIdA();
	const ObjectId& b = collisionData.getObjectIdB();

	Score* p1Score = static_cast<Score*>(gameObjectSystem.editProperty(Score::SCORE_ID, "bump1"));
	Score* p2Score = static_cast<Score*>(gameObjectSystem.editProperty(Score::SCORE_ID, "bump2"));
	
	const GameRulesComponent* rulesComp = static_cast<const GameRulesComponent*>(gameObjectSystem.getComponent("Rules"));

	if ( ( a == StringHash("wall1") && b == StringHash("ball1") ) || (a == StringHash("ball1") && b == StringHash("wall1")))
	{
		p2Score->setScore(p2Score->getScore()+1);
		LOG(INFO) << "Score changes: P1 -> " << p1Score->getScore() << " | P2 -> " << p2Score->getScore() << ".";
		if ( p2Score->getScore() < GameRulesComponent::SCORE_THRESHOLD ) {
			rulesComp->resetBallAndBumpers();
			m_StaticBumper = false;
			m_rebounds = 0;
		}
	}
	else if ((a == StringHash("wall2") && b == StringHash("ball1")) || (a == StringHash("ball1") && b == StringHash("wall2")))
	{
		p1Score->setScore(p1Score->getScore()+1);
		LOG(INFO) << "Score changes: P1 -> " << p1Score->getScore() << " | P2 -> " << p2Score->getScore() << ".";
		if ( p1Score->getScore() < GameRulesComponent::SCORE_THRESHOLD ) {
			rulesComp->resetBallAndBumpers();
			m_StaticBumper = false;
			m_rebounds = 0;
		}
	}
	else if ( m_rebounds < GameRulesComponent::REBOUNDS_THRESHOLD )
	{
		if ( a == StringHash("bump1") || a == StringHash("bump2") || b == StringHash("bump1") || b == StringHash("bump2") )
		{
			m_rebounds++;
		}
	}
	else if ( !m_StaticBumper )
	{
		m_StaticBumper = true;
		Bumper::move("bumpS", vector3(0.f, 0.f, 0.f));
	}
}

void GameState::checkBallHorizontalVelocity() {
	PhysicsBody* ballPhysicsBody = static_cast<PhysicsBody*>(GameObjectSystem::GetSingleton().editProperty(PhysicsBody::PHY_BODY_ID, "ball1"));
	btVector3 ballVelocity = ballPhysicsBody->editBody()->getLinearVelocity();
	btScalar curXVel = ballVelocity.getX();

	if (abs(curXVel) < Ball::MIN_HORIZONTAL_SPEED ) {
		LOG(INFO) << "Horizontal speed lower than threshold. Rising it to " << Ball::MIN_HORIZONTAL_SPEED;
		float forcedXVel = (curXVel > 0.f ? Ball::MIN_HORIZONTAL_SPEED : -Ball::MIN_HORIZONTAL_SPEED);
		ballPhysicsBody->setVelocity(vector3(forcedXVel, ballVelocity.y(), 0));
	}

}